package com.ft.oa.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.ft.oa.domain.dto.sys.MenuDto;
import com.ft.oa.domain.sys.SysAuth;
import com.ft.oa.domain.sys.SysRole;
import com.ft.oa.domain.sys.SysRoleAuth;
import com.ft.oa.mapper.sys.SysAuthMapper;
import com.ft.oa.mapper.sys.SysRoleAuthMapper;
import com.ft.oa.service.sys.SysAuthService;
import com.ft.oa.service.sys.SysRoleService;
import com.ft.oa.utils.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysAuthServiceImpl implements SysAuthService {

    @Resource
    private SysAuthMapper sysAuthMapper;
    @Resource
    private SysRoleAuthMapper sysRoleAuthMapper;
    @Resource
    private SysRoleService sysRoleService;

    @Override
    public List<MenuDto> menuTree() {
        List<SysAuth> authList = new ArrayList<>();
        //用户菜单
        //if ("admin".equalsIgnoreCase(SecurityUtils.getCurrentUser().getUsername())) {
        //    QueryWrapper<SysAuth> wrapper = new QueryWrapper<>();
        //    wrapper.lambda().eq(SysAuth::getDel, false);
        //    //.eq(SysAuth::getHidden, false);
        //    authList = sysAuthMapper.selectList(wrapper);
        //}else{
        //    List<SysRole> roles = sysRoleService.userRoles(SecurityUtils.getCurrentUser().getId());
        //    authList = roleAuths(roles.stream().map(SysRole::getId).collect(Collectors.toSet()));
        //}
        //放开权限 TODO
        QueryWrapper<SysAuth> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SysAuth::getDel, false);
        //.eq(SysAuth::getHidden, false);
        authList = sysAuthMapper.selectList(wrapper);

        List<MenuDto> menuDtoList = authList.stream().filter(e -> e.getType() != 2).map(MenuDto::authToMenu).collect(Collectors.toList());
        Map<Integer, List<MenuDto>> groupByPid = menuDtoList.stream()
                .collect(Collectors.groupingBy(MenuDto::getPid));
        menuDtoList.forEach(
            e -> {
                if (groupByPid.containsKey(e.getId())) {
                    e.setChildren(groupByPid.get(e.getId()));
                }
            }
        );
        List<MenuDto> tree = groupByPid.get(0);
        List<MenuDto> result = tree.stream().sorted(Comparator.comparing(MenuDto::getLevel)).collect(Collectors.toList());

        return result;
    }

    @Override
    public List<MenuDto> menuTreeNew() {
        List<SysAuth> authList = new ArrayList<>();
        //用户菜单
        if ("admin".equalsIgnoreCase(SecurityUtils.getCurrentUser().getUsername())) {
            QueryWrapper<SysAuth> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(SysAuth::getDel, false)
                    .eq(SysAuth::getHidden, false);
            authList = sysAuthMapper.selectList(wrapper);
        }else{
            List<SysRole> roles = sysRoleService.userRoles(SecurityUtils.getCurrentUser().getId());
            authList = roleAuthsNew(roles.stream().map(SysRole::getId).collect(Collectors.toSet()));
        }

        List<MenuDto> menuDtoList = authList.stream().filter(e -> e.getType() != 2).map(MenuDto::authToMenu).collect(Collectors.toList());
        Map<Integer, List<MenuDto>> groupByPid = menuDtoList.stream()
                .collect(Collectors.groupingBy(MenuDto::getPid));
        menuDtoList.forEach(
                e -> {
                    if (groupByPid.containsKey(e.getId())) {
                        e.setChildren(groupByPid.get(e.getId()));
                    }
                }
        );
        List<MenuDto> tree = groupByPid.get(0);
        List<MenuDto> result = tree.stream().sorted(Comparator.comparing(MenuDto::getLevel)).collect(Collectors.toList());
        return result;
    }

    private List<SysAuth> roleAuthsNew(Set<Integer> roleIds) {
        QueryWrapper<SysRoleAuth> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .in(SysRoleAuth::getRoleId, roleIds);

        List<SysRoleAuth> sysRoleAuths = sysRoleAuthMapper.selectList(wrapper);

        List<SysAuth> authList = sysAuthMapper.selectBatchIds(sysRoleAuths.stream().map(SysRoleAuth::getAuthId).collect(Collectors.toSet()));
        return authList;
    }
    @Override
    public List<SysAuth> top() {
        QueryWrapper<SysAuth> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysAuth::getPid, 0)
                .eq(SysAuth::getDel, false);

        List<SysAuth> authList = sysAuthMapper.selectList(wrapper);
        List<SysAuth> sorted = authList.stream().sorted(Comparator.comparing(SysAuth::getLevel)).collect(Collectors.toList());
        return sorted;
    }

    @Override
    @Transactional
    public void edit(SysAuth sysAuth) {
        LambdaUpdateChainWrapper<SysAuth> wrapper = new LambdaUpdateChainWrapper<>(sysAuthMapper);
        LocalDateTime now = LocalDateTime.now();
        boolean update = wrapper.eq(SysAuth::getId, sysAuth.getId())
                .set(SysAuth::getHidden, sysAuth.getHidden())
                .set(SysAuth::getTitle, sysAuth.getTitle())
                .update();
    }

    @Override
    @Transactional
    public void del(Integer id) {
        LambdaUpdateChainWrapper<SysAuth> wrapper = new LambdaUpdateChainWrapper<>(sysAuthMapper);
        boolean update = wrapper.eq(SysAuth::getId, id)
                .set(SysAuth::getDel, true)
                .update();
    }

    @Override
    @Transactional
    public void menuUp(Integer id) {

        menuLevel(id, true);

    }

    @Override
    @Transactional
    public void menuDown(Integer id) {

        menuLevel(id, false);
    }

    //此处需加锁,若为单体部署,可用synchronize，若多实例部署需加分布式锁
    private synchronized void menuLevel(Integer authId, boolean up){


        SysAuth sysAuth = sysAuthMapper.selectById(authId);

        QueryWrapper<SysAuth> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysAuth::getPid, sysAuth.getPid())
                .eq(SysAuth::getLevel, up ? sysAuth.getLevel()-1 : sysAuth.getLevel()+1);
        SysAuth one = sysAuthMapper.selectOne(wrapper);

        if(one != null){
            one.setLevel(up ? one.getLevel() + 1 : one.getLevel() - 1);
            sysAuth.setLevel(up ? sysAuth.getLevel() - 1: one.getLevel() + 1);

            sysAuthMapper.updateById(one);
            sysAuthMapper.updateById(sysAuth);
        }
    }

    @Override
    public List<SysAuth> roleAuths(Set<Integer> roleIds) {

        QueryWrapper<SysRoleAuth> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .in(SysRoleAuth::getRoleId, roleIds);

        List<SysRoleAuth> sysRoleAuths = sysRoleAuthMapper.selectList(wrapper);

        List<SysAuth> authList = sysAuthMapper.selectBatchIds(sysRoleAuths.stream().map(SysRoleAuth::getAuthId).collect(Collectors.toSet()));
        return authList;
    }

    @Override
    public List<SysAuth> tree() {
        QueryWrapper<SysAuth> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysAuth::getDel, false)
                .eq(SysAuth::getHidden, false);

        List<SysAuth> authList = sysAuthMapper.selectList(wrapper);

        Map<Integer, List<SysAuth>> groupByPid = authList.stream()
                .collect(Collectors.groupingBy(SysAuth::getPid));

        authList.forEach(
                e -> {
                    if(groupByPid.containsKey(e.getId())){
                        e.setChildren(groupByPid.get(e.getId()));
                    }
                }
        );

        List<SysAuth> tree = groupByPid.get(0);
        return tree;
    }
}
